/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package nsip.components.ds;

import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import nsip.model.Item;
import nsip.model.ItemStatus;
import nsip.model.ItemType;
import nsip.transport.NsipTransport;

/**
 * Generic database which stores orders as well as connected rfqs and offers.
 * May be used both on the customer and on the supplier side.
 * 
 * @author nico.rehwaldt
 */
public class OrderDataBase {
    
    protected final Logger logger;
    
    protected EnumMap<ItemType, Map<Integer, Item>> itemsMap = new EnumMap(ItemType.class) {{
        for (ItemType t: ItemType.values()) {
            put(t, new LinkedHashMap());
        }
    }};
    
    private final String ident;
    private final NsipTransport transport;
    private final StatisticDataBase statistics;

    private Collection<Item> orders = orderMap().values();
    
    /**
     * Creates a new order database which is connected to the specified
     * information system.
     *
     * @param is
     * @param ident
     */
    public OrderDataBase(String ident, NsipTransport transport, StatisticDataBase statistic) {
        this.logger = Logger.getLogger("OrderManager[" + ident + "]");
        this.ident = ident;
        this.statistics = statistic;
        this.transport = transport;
    }

    /**
     * Adds a managable order to the database, namely an {@link Item}.
     *
     * @param entity
     */
    public void add(Item entity) {
        checkSetID(entity);
        
        ItemType etype = entity.getType();
        
        Map<Integer, Item> map = itemsMap.get(etype);
        if (map.containsKey(entity.getId())) {
            throw new IllegalStateException("Tried to add " + entity + " twice");
        }
        
        map.put(entity.getId(), entity);
        
        statistics.counters().increment(ident + "_" + entity.getType());
    }

    /**
     * Returns an entity with the specific type
     * 
     * @param type
     * @param id
     * @return
     */
    public Item get(ItemType type, int id) {
        return itemsMap.get(type).get(id);
    }

    /**
     * Sets an id on the item if it does not yet have one
     * @param item
     */
    protected void checkSetID(Item item) {
        Item.checkSetID(item, transport);
    }

    /**
     * Return a map of orders in this data base
     * @return
     */
    public Map<Integer, Item> orderMap() {
        return itemsMap.get(ItemType.ORDER);
    }

    /**
     * Return a map of offers in this data base
     * @return
     */
    public Map<Integer, Item> offerMap() {
        return itemsMap.get(ItemType.OFFER);
    }

    /**
     * Return a map of rfqs in this data base
     * @return
     */
    public Map<Integer, Item> rfqMap() {
        return itemsMap.get(ItemType.RFQ);
    }

    /**
     * Return a list of all active orders in the database
     * @return
     */
    public List<Item> getOrders(ItemStatus ... states) {
        List<Item> result = new LinkedList();
        Iterator<Item> iterator = orders.iterator();

        while (iterator.hasNext()) {
            Item i = iterator.next();
            
            for (ItemStatus status: states) {
                if (i.hasStatus(status)) {
                    result.add(i);
                    break;
                }
            }
        }

        Collections.sort(result, new Comparator<Item>() {
            public int compare(Item o1, Item o2) {
                return (new Integer(o1.getDueDate()).compareTo(o2.getDueDate()));
            }
        });
        
        return result;
    }
}
